﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Xms.Abp.Application.Services;
using Xms.Abp.Authorization;
using Xms.Abp.BackgroundJob;
using Xms.Abp.Domain.Repositories;
using Xms.Abp.MultiTenancy;

namespace BackgroundJobManagement;

[PermissionsUse(typeof(BackgroundJobPermissions))]
public class BackgroundJobAppService : XmsCrudAppService<BackgroundJobEntity, BackgroundJobResult, Guid, BackgroundJobsPagedParameter, BackgroundJobCreateParameter, BackgroundJobUpdateParameter>, IBackgroundJobAppService
{
    protected IMultiTenantStore MultiTenantStore
        => LazyInject<IMultiTenantStore>();
    protected IXmsRepository<BackgroundScheduleEntity, Guid> ScheduleRepository
        => LazyInject<IXmsRepository<BackgroundScheduleEntity, Guid>>();
    public BackgroundJobAppService(IXmsRepository<BackgroundJobEntity, Guid> repository) : base(repository)
    {
    }

    protected override Func<BackgroundJobCreateParameter, BackgroundJobEntity> EntityCreator => input => new BackgroundJobEntity(GuidGenerator.Create());

    protected override async Task<IQueryable<BackgroundJobEntity>> CreateFilteredQueryAsync(BackgroundJobsPagedParameter input)
    {
        var query = await base.CreateFilteredQueryAsync(input);
        query = query.WhereIf(!input.Filter.IsNullOrWhiteSpace(), r => r.Name.Contains(input.Filter) || r.DisplayName.Contains(input.Filter));
        query = query.WhereIf(input.ScheduleId.HasValue, r => r.ScheduleId == input.ScheduleId);
        return query;
    }

    protected override async Task FullingResultDetailsAsync<TResult>(IEnumerable<TResult> results)
    {
        await base.FullingResultDetailsAsync(results);
        var list = results.OfType<BackgroundJobResult>().ToList();
        if (list.Any())
        {
            var tenant = (await MultiTenantStore.GetAllAsync()).Select(r => new { r.Id, r.DisplayName }).ToDictionary(r => r.Id, r => r.DisplayName);
            var scheduleIds = list.Select(r => r.ScheduleId).Where(r => r.HasValue).ToList();
            var schedules = (await (await ScheduleRepository.AsNoTrackingAsync()).Where(r => scheduleIds.Contains(r.Id)).Select(r => new { r.Id, r.DisplayName }).ToListAsync()).ToDictionary(r => r.Id, r => r.DisplayName);
            foreach (var item in list)
            {
                if (item.TenantId.HasValue && tenant.ContainsKey(item.TenantId.Value))
                {
                    item.TenantName = tenant[item.TenantId.Value];
                }
                if (item.ScheduleId.HasValue && schedules.ContainsKey(item.ScheduleId.Value))
                {
                    item.ScheduleName = schedules[item.ScheduleId.Value];
                }
            }
        }
    }

    public async Task RestartAsync(Guid id)
    {
        var oldJob = await (await Repository.GetQueryableAsync()).FirstOrDefaultAsync(r => r.Id == id);
        if (oldJob == null)
        {
            throw new UserFriendlyException("任务不存在");
        }
        var job = new BackgroundJobEntity(GuidGenerator.Create())
        {
            BackgroundJobStatus = BackgroundJobStatus.Waiting,
            Name = oldJob.Name,
            DisplayName = oldJob.DisplayName.RemovePostFix("（重试）") + "（重试）",
            JobArgs = oldJob.JobArgs,
            LastTryTime = oldJob.LastTryTime,
            MaxTryCount = oldJob.MaxTryCount,
            NextTryTime = DateTime.Now,
            Priority = oldJob.Priority,
            RetryIntervals = oldJob.RetryIntervals,
            ScheduleId = oldJob.ScheduleId,
            ReferenceJobs = oldJob.ReferenceJobs,
            Remark = oldJob.Remark,
            Timeout = oldJob.Timeout,
            TryCount = 0,
        };
        foreach (var key in oldJob.ExtraProperties.Keys)
        {
            job.ExtraProperties[key] = oldJob.ExtraProperties[key];
        }
        await Repository.InsertAsync(job, true);
        await Repository.DeleteAsync(oldJob, true);
    }
}
